<?php
include_once 'Retriever.php';
include_once '../Model/BusAtStop.php';
include_once '../Model/BusLine.php';
include_once '../Utility/simplehtmldom/simple_html_dom.php';
include_once '../Exceptions/CommunicationException.php';
include_once '../Exceptions/WrongParametersException.php';

include_once '../AtacAPI/Auth.php';
include_once '../AtacAPI/Paline.php';


class ACBusWaitingTimes extends Retriever {
	
	//Questi due parametri si sono rivelati inutili, posso anche non specificarli nell'indirizzo
	//private static $NAV = '2';
	//private static $SUBMIT = 'Invia';
	
	private static $SERVICE_NAME = 'paline';
	private static $PLUS = '+';
	private static $SEPARATOR = '&';
	private static $ATAC_URL = 'http://muovi.roma.it/?';
	
	
	private static $NAV = '2';
	private static $SUBMIT = 'Invia';
	private static $ACTION_FOR_STOP_ID = 'dettaglio';
	private static $ACTION_FOR_LINE_ID = 'dettaglio_linea';
	private static $ACTION_FOR_LINE_DIRECTION = 'dettaglio_linea_percorso';
	
	private static $BUS_FLAG = 'Fermate';
	private static $CLOSE_BUS_FLAG = 'Arrivo';
	private static $TERMINUS_FLAG = 'Capolinea';
	
	
	
	//Questo � il vettore dei parametri da utilizzare nel caso in cui si disponga dell'id fermata
	private $paramsWithStopID;
	
	//Se invece si sta eseguendo una navigazione bisogna si accede prima tramite l'id della LINEA
	//e si utilizza questo vettore di parametri
	private $paramsWithLineID;
	
	//Il secondo livello di navigazione dopo aver scelto la linea, prevede la scelta della direzione e 
	//l'utilizzo di questo vettore
	private $paramsWithLineDirection;
	
	/**
	 * NB: l'ultimo livello di navigazione � accessibile una volta scelta la fermata.
	 * Tale fermata viene specificata da una lista di fermate tramite l'identificativo atac (StopID)
	 * L'ultimo livello di navigazione pertanto si riconduce al primo caso e possiamo riutilizzare il 
	 * vettore dei parametri $paramsWithStopIDAccess
	 */
	
	private $stopID;
	private $busLine;
	private $direction;
	//E' la direzione espressa come locazione, cio� come capolinea, quindi un oggetto di tipo BusStop
	private $directionAsLocation;
	//La lista degli autobus in arrivo per la fermata
	private $buses;
	
	
	function __construct() {
		
		//Creo il vettore dei parametri per il primo tipo di richiesta ad atac, � la richiesta
		//che specifica direttamente l'id fermata
		$this->paramsWithStopID = array(
			'id_fermata'=>null,
			'service'=> ACBusWaitingTimes::$SERVICE_NAME,
			//'nav'=> ACBusWaitingTimes::$NAV,
			'action'=> ACBusWaitingTimes::$ACTION_FOR_STOP_ID,
			//'submit'=> ACBusWaitingTimes::$SUBMIT
		);
		
		
		//Creo il vettore dei parametri per la richiesta che rappresenta il primo livello di navigazione
		//specificando quindi la linea desiderata
		$this->paramsWithLineID = array(
			'id_linea'=>null,
			'service'=> ACBusWaitingTimes::$SERVICE_NAME,
			'action'=> ACBusWaitingTimes::$ACTION_FOR_LINE_ID,
			'nav'=> ACBusWaitingTimes::$NAV,
			'submit'=> ACBusWaitingTimes::$SUBMIT
		);
		
		//Creo il vettore dei parametri per la richiesta che rappresenta il secondo livello di navigazione
		//specificando quindi la direzione per la linea selezionata in precedenza
		$this->paramsWithLineDirection = array(
			'percorso'=>null,
			'service'=> ACBusWaitingTimes::$SERVICE_NAME,
			//'nav'=> ACBusWaitingTimes::$NAV,
			'action'=> ACBusWaitingTimes::$ACTION_FOR_LINE_DIRECTION,
			//'submit'=> ACBusWaitingTimes::$SUBMIT
		);
		
		$this->buses = null;
	}
	
	
	private function addBusToList($bus) {
		
		if ($bus instanceOf BusAtStop)
		{
		
			if ($this->buses==null)
			{
				$this->buses = array($bus);	
			}
			else
				array_push($this->buses,$bus);
		}
		else
			throw new WrongParametersException("Class: ACBusWaitingTimes. Method: addBusToList($bus). 
			Parameter must be BusAtStop type");
	}
	
	private function sortBuses($buses) {
		if (count($buses)==0) return null;
		if (count($buses)==1) return $buses;
		$subi=0;
		$subip1=0;
		$high = count($buses);
  		while ($high > 0) 
  		{
    		for ($i=0;$i<$high-1;$i++)
    		{
      			if ($buses[$i]->getTimeLeft()=="")
      				$subi=$buses[$i]->getStopsLeft();
      			else
      				$subi=$buses[$i]->getTimeLeft();
      				
      				
      			if ($buses[$i+1]->getTimeLeft()=="")
      				$subip1=$buses[$i+1]->getStopsLeft();
      			else
      				$subip1=$buses[$i+1]->getTimeLeft();
    			
    			if ($subi > $subip1) { 
        			$tmp = $buses[$i];
        			$buses[$i] = $buses[$i+1]; 
        			$buses[$i+1] = $tmp;
      			}
    		}
    		$high = $high-1;
  		}
		
  		return $buses;
		
	}
	
	
	
	private function strToBusObject($rawStr, $busStop) {
		
		$path = null;
		//Cerco il tag <a> nel codice presente in $rawStr
		$res = $rawStr->find('a');
		if (isset($res[0]))
		{
			/**Se � presente il tag <a>, allora sar� di questo tipo
			 * <a href="atacmobile.php?nav=3&amp;service=paline&amp;
			 * action=dettaglio_linea_percorso&amp;fermata=74635&amp;
			 * percorso=3601&amp;t=pal#pal">719</a>
			 * Ci serve la parte che riguarda il percorso, cio�, nell'esempio: percorso=3601
			 * 
			 */
			$href = $res[0];
			//Serpariamo le sottostringe tra i punti e virgola e prendiamo la quinta (@author:matteo divido con "\" e ottengo il codice del percorso)
			$parts = explode("/",$href->outertext);
			$app = $parts[3];
			//Abbiamo ottenuto "percorso=3601&amp". Ora separiamo per uguale e leviamo gli ultimi
			//4 caratteri
			$app = explode("?",$app);
			$path = $app[0];//substr($app[1],0,strlen($app[1])-4);
			$params = explode("&amp;",$app[1]);
			foreach($params as $param){
				$temp = explode("=",$param);
				if($temp[0] == "id_veicolo"){
					$lineID = $temp[1];
				}
			}
			//$res[0]->clear();
			unset($res[0]);
			
		}
		else //Se non c'� tag a vuol dire che l'autobus per quella linea non sta circolando
		{
			//<div class="banda2"><span class="b">771:</span> Nessun autobus<br />
			//echo "<br>".$rawStr->plaintext."<br>";
			$str = $rawStr->plaintext;
			$parts = explode(":",$str);
			$line = trim($parts[0]);
			if (stristr($line, " "))
			{
				$app = explode(" ",$line);
				$line = trim($app[0]);
			}
			$lineObject = new BusLine($line);
			$bus = new BusAtStop($lineObject,null,$busStop, 10000, 10000);
			//$rawStr->clear();
			//unset($rawStr);
			$lineID = null;
			return $bus;
			
		}
		
		
		
		
		$str = $rawStr->plaintext;
		$str=str_replace("&#39","",$str);
		
		//Tramite explode, utilizzando i due punti come separatore, ottengo due sottostringe
		//La prima � gi� pronta, e rappresenta il numero di linea
		//
		
		$parts = explode(":",$str);
		$line = trim($parts[0]);
		if (stristr($line, " "))
		{
			$app = explode(" ",$line);
			$line = trim($app[0]);
		}
		$lineObject = new BusLine($line);
		$other = $parts[1];
		if (stristr($other,ACBusWaitingTimes::$CLOSE_BUS_FLAG) != false)
		{
			/**
			 * Sono nel caso: 719: In Arrivo
			 * 
			 */
			//$rawStr->clear();
			//unset($rawStr);
			$bus = new BusAtStop($lineObject,$lineID,$busStop, 0, 0, $path);
			return $bus;	
		}
		else
		{
			if (stristr($other,ACBusWaitingTimes::$BUS_FLAG) != false)
			{
				$otherParts=explode(" ",$other);
				$stopsLeft = trim($otherParts[0]);
				$minutesWithParentesis = rtrim($otherParts[2]);
				$minutes = substr($minutesWithParentesis,1,strpos($minutesWithParentesis,")")-2);
	
				//$rawStr->clear();
				//unset($rawStr);
				
				
				$bus = new BusAtStop($lineObject,$lineID,$busStop, $stopsLeft, $minutes, $path);
				
				//echo $line.": ".$stopsLeft." - ".$minutes."<br>";
				
				return $bus;
			}
			else 
				if (stristr($other,ACBusWaitingTimes::$TERMINUS_FLAG) != false)
				{	
					/**
					 * Sono nel caso: "Capolinea (partenza 23:34)"
					 * Prendo tutto quello che c'� dal penultimo carattere, a ritroso di 4
					 * 23:34
					 */
					
					//Sono sicuro che esista parts[2] perch� ci sono anche i due punti dell'orario
					//Quindi ricompongo la mia stringa
					$completeString = $other.":".$parts[2];
					$center = strpos($completeString,":");
					$time = substr($completeString,$center-2,5);
					
					//$rawStr->clear();
					//unset($rawStr);
					
					
					$bus = new BusAtStop($lineObject,$lineID,$busStop, 1000, 1000, $path,$time);
					return $bus;
				}
		}
		
		//$rawStr->clear();
		//unset($rawStr);
		
		//In tutti gli altri casi
		$bus = new BusAtStop($lineObject,$lineID,$busStop, -1, -1, $path);
		return $bus;
		


	}

	
	function getIncomingBusesAtStop_NEW($busStop) {
		unset($this->buses);
		$this->buses = null;
		$authentication = new Authentication;
		$authentication->requestToken();
		$token_string = $authentication->getToken();

		$paline = new Paline($token_string);
		$listVeicoli = $paline->getVeicoli($busStop->getAtacID());

		if (count($listVeicoli) > 0)
		{
			$first_capolinea = true;
			$current_linea = $listVeicoli[0];
			$prev_linea = $current_linea;
			foreach ($listVeicoli as $veicolo) {
				$lineObject = new BusLine($veicolo->getLinea());
				$current_linea = $veicolo->getLinea();

				if ($current_linea != $prev_linea)
				{
					$prev_linea = $current_linea;
					$first_capolinea = true;
				}
				if ($veicolo->isCapolinea() && $first_capolinea == true )
				{
					if ($current_linea == $prev_linea)
					{
						$first_capolinea = false;
						$partenza = $paline->getProssimaPartenza($veicolo->getIdPercorso());
						$center = strpos($partenza,":");
						$time = substr($partenza,$center-2,5);
						$bus = new BusAtStop($lineObject, $veicolo->getIdVeicolo(), $busStop, 1000, 1000, $veicolo->getIdPercorso(),$time);
						$this->addBusToList($bus);
					}
				}
				else if ($veicolo->isInArrivo())
				{
					$bus = new BusAtStop($lineObject, $veicolo->getIdVeicolo(), $busStop, 0, 0, $veicolo->getIdPercorso());
					$this->addBusToList($bus);
				}
				else if (!$veicolo->isCapolinea())
				{
					$other = $veicolo->getAnnuncio();
					$otherParts=explode(" ",$other);
					$stopsLeft = trim($otherParts[0]);
					$minutesWithParentesis = rtrim($otherParts[2]);
					$minutes = substr($minutesWithParentesis,1,strpos($minutesWithParentesis,")")-2);

					$bus = new BusAtStop($lineObject, $veicolo->getIdVeicolo(), $busStop, $stopsLeft, $minutes, $veicolo->getIdPercorso());
					$this->addBusToList($bus);
				}
			}

		}
		$this->buses = $this->sortBuses($this->buses);
			
		return $this->buses;
	}
	
	
	
	/**
	 * Rende una lista di oggetti BusAtStop che rappresentano gli autobus in arrivo alla fermata specificata
	 * Il parametro deve essere di tipo BusStop o verr� lanciata un'eccezione
	 * @param BusStop $busStop
	 * @return una lista di oggetti di tipo Bus, null se avviene un errore, lista di zero elementi
	 * 			se non ci sono autobus in arrivo
	 * @throws CommunicationException se la richiesta dei dati da atac non va a buon fine
	 */
	function getIncomingBusesAtStop($busStop) {
		if ($busStop instanceOf BusStop)
		{
			unset($this->buses);
			$this->buses = null;
			$atacID = $busStop->getAtacID();
			$this->paramsWithStopID['id_fermata'] = $atacID; 
			//Costruisco l'url con i parametri giusti
			//$url= ACBusWaitingTimes::$ATAC_URL;
			//foreach($this->paramsWithStopID as $key => $value)
				//$url = $url."&".$key."=".$value;
			$url = "http://muovi.roma.it/paline/palina/".$atacID;
			$page = $this->getHTMLPageFromURL($url);
			if ($page==false)
			{
				//throw new CommunicationException ("ACBusWaitingTimes: No Response from ATAC", 0);
				return null;
			}
			
			$html = str_get_html($page);
			
			$text = $html->plaintext;
			
			$pos = strpos($text,"servizio");
			$pos2 = strpos($text,"attivo");
			$pos3 = strpos($text,"non");
			//Il problema riguarda l'intero servizio
			if(($pos != false) && ($pos2!=false) && ($pos3!=false)) {
 				throw new CommunicationException ("ACBusWaitingTimes: No Response from ATAC", 0);
				return null;
			}
			//Il problema riguarda solo quella richiesta
			if ((strpos($text, "tecnici")!=false) && ((strpos($text, "problemi")!=false))) {
				//throw new CommunicationException ("ACBusWaitingTimes: Service Not Available", 0);
				return null;
			}
			
			//echo "<br><br>########### TEXT ##################<br><br>";
			//echo $text;
			
			$ret0 = $html->find('div[class=banda0]');
			if ($ret0 == null)
			{
				//Libero memoria e rendo null
				unset($ret0);
				$html->clear();
				unset($html);
				
				return null;
			}
			$this->addBusToList($this->strToBusObject($ret0[0], $busStop));
			$ret0[0]->clear();
			unset($ret0[0]);
			unset($ret0);
			
			/**
			 * Ogni elemento nel vettore restituito da find ha un metodo plaintext che restituisce
			 * il contenuto della parte di pagina che � stato trovato. 
			 * La stringa restituita da plaintext � di una delle due forme seguenti:
			 * 
			 * 719: 20 Fermate (18')
			 * 775: Nessun autobus
			 * 
			 * Cio� numero linea, seguito da due punti, e poi una seconda parte da analizzare che pu�
			 * essere 
			 * 	" Nessun autobus" 
			 * 		oppure 
			 *  "<spazio><numerofermate>"Fermate"<parentesi><numerominuti>"'"<parentesichiusa> 
			 */	
			$ret1 = $html->find('div[class=banda1]');
			//echo "<br><br>Banda1. Trovati:".count($ret1)."<br>";
			for($i=0;$i<count($ret1);$i++)
			{
				$this->addBusToList($this->strToBusObject($ret1[$i], $busStop));
				$ret1[$i]->clear();
				//unset($ret1[$i]);	
			
			}
			unset($ret1);
			//echo "<br><br>__________________________________________<br><br>";
				
			
			$ret2 = $html->find('div[class=banda2]');
			//echo "<br><br>Banda2. Trovati:".count($ret2)."<br>";
			//echo "<br>";
			for($i=0;$i<count($ret2);$i++)
			{
				$this->addBusToList($this->strToBusObject($ret2[$i],$busStop));
				$ret2[$i]->clear();
				//unset($ret2[$i]);	
				
			}
			unset($ret2);	
			//echo $html->plaintext;
			//echo "<br><br>__________________________________________<br><br>";

			foreach ($this->buses as $bus)
			{
				if (($bus->getTimeLeft() == -1) && ($bus->getTimeLeft() == -1) ) {
					$bus->setTimeLeft(999);
					$bus->setStopsLeft(999);
				}
				
			}
			
			$this->buses = $this->sortBuses($this->buses);
			
			
			$html->clear();
			unset($html);
			
			return $this->buses;
			
		}
		else
			throw new Exception ("ACBusWaitingTimes: Parameters MUST be BusStop type");
		
	}
	
	

	function getPathIDsForLineNumber_NEW($lineNumber)
	{
		$authentication = new Authentication;
                $authentication->requestToken();
                $token_string = $authentication->getToken();

                $paline = new Paline($token_string);
                $listPercorsi = $paline->getPercorsi($lineNumber);
		$pathIDs = array();
		foreach($listPercorsi as $percorso)
		{
			array_push($pathIDs, $percorso->getIdPercorso());
		}
		return $pathIDs;
	}

	/**
	 * Restituisce i pathID per una data linea specificata come parametro
	 * @param string $lineNumber
	 * @return array: un'array di stringhe che sono gli identificatori dei percorsi seguiti da quella linea
	 */
	function getPathIDsForLineNumber($lineNumber)
	{
		//$this->paramsWithLineID['id_linea'] = $lineNumber;
		//$url= ACBusWaitingTimes::$ATAC_URL;
		//foreach($this->paramsWithLineID as $key => $value)
			//$url = $url."&".$key."=".$value;
		$url = "http://muovi.roma.it/paline/?cerca=".$lineNumber; //forse deve diventare "cerca="
			
		//echo "<br>URL:".$url;
			
		//Ottengo la pagina html corrispondente all'url costruito
		$page = $this->getHTMLPageFromURL($url);
		
		if ($page==false)
		{
			throw new CommunicationException ("ACBusWaitingTimes: No Response from ATAC", 0);
			return null;
		}
		
		//echo "<br>Prima di str_get_html";
		
		$html = str_get_html($page);
		
		
		
		$text = $html->plaintext;
		
		$pos = strpos($text,"servizio");
		$pos2 = strpos($text,"attivo");
		$pos3 = strpos($text,"non");

		//Il problema riguarda l'intero servizio
		if(($pos != false) && ($pos2!=false) && ($pos3!=false)) {
 			$html->clear();
			unset($html);
			
			throw new CommunicationException ("ACBusWaitingTimes: No Response from ATAC", 0);
			return null;
		}
		
		//Il problema riguarda solo quella richiesta
		if ((strpos($text, "tecnici")!=false) && ((strpos($text, "problemi")!=false))) {
			$html->clear();
			unset($html);
			
			return null;
		}

		
		//ottento l'oggetto che mi permette di analizzare la pagina html
		$mainDiv = $html->find('div[id=main]');
		if($mainDiv)
			$links = $mainDiv[0]->find('a');
		else
			die("errore");
				
		if (!isset($links[0]))
		{
			$html->clear();
			unset($html);
			return null;
		}
		
		$i=0;
		$pathIDs = array();
		for($i=0;$i<count($links);$i++) {
			//echo "<br>percorso:".$links[$i];
			$parts = explode(";",$links[$i]);
			$app = $parts[0];
			$app = explode("/",$app);
			$app2 = explode("?",$app[3]);
			$pathID = $app2[0];//substr($app[1],0,strlen($app[1])-4);
			array_push($pathIDs, $pathID);
			
		}
		
		$html->clear();
		unset($html);
		return $pathIDs;
	}
	

	function getPath_NEW($pathID)
	{
		$authentication = new Authentication;
		$authentication->requestToken();
		$token_string = $authentication->getToken();

		$paline = new Paline($token_string);
		$listFermate = $paline->getFermate($pathID);
		if (count($listFermate)>0)
			$path = array();
		else
			$path = null;
		
		foreach($listFermate as $fermata)
		{
			$stop = new BusStop($fermata->getNome(), $fermata->getIdPalina());
			array_push($path,$stop);
		}
		
		$busPath = new BusLinePath($path, $pathID);
		return $busPath;
	}	
	
	
	function getPath($pathID)
	{		
	
		//$this->paramsWithLineDirection['percorso'] = $pathID; 
		//Costruisco l'url con i parametri giusti
		//$url= ACBusWaitingTimes::$ATAC_URL;
		//foreach($this->paramsWithLineDirection as $key => $value)
			//$url = $url."&".$key."=".$value;
		$url = "http://muovi.roma.it/paline/percorso/".$pathID;
			
		//Ottengo la pagina html corrispondente all'url costruito
		$page = $this->getHTMLPageFromURL($url);
		//ottento l'oggetto che mi permette di analizzare la pagina html
		$html = str_get_html($page);
		
		if ($page==false)
		{
			throw new CommunicationException ("ACBusWaitingTimes: No Response from ATAC", 0);
			return null;
		}
		
		
		
		$text = $html->plaintext;
		
		$pos = strpos($text,"servizio");
		$pos2 = strpos($text,"attivo");
		$pos3 = strpos($text,"non");

		//Il problema riguarda l'intero servizio
		if(($pos != false) && ($pos2!=false) && ($pos3!=false)) {
 			throw new CommunicationException ("ACBusWaitingTimes: No Response from ATAC", 0);
			return null;
		}
		
		//Il problema riguarda solo quella richiesta
		if ((strpos($text, "tecnici")!=false) && ((strpos($text, "problemi")!=false))) {
			//throw new CommunicationException ("ACBusWaitingTimes: Service Not Available", 0);
			return null;
		}
				
		$mainDiv = $html->find('div[id=main]');
		$links = $mainDiv[0]->find('a');
		
		if (count($links)>0)
			$path = array();
		else
			$path = null;
					
		for ($i=0;$i<count($links);$i++)
		{
			$stopName = $links[$i]->plaintext;
			
			$parts = explode(";",$links[$i]);
			$app = $parts[0];
			$app2 = explode("/",$app);
			$service = $app2[2];
			$app3 = explode("?",$app2[3]);
			$stopID = $app3[0];

			if($service=='palina'){
				$stop = new BusStop($stopName, $stopID);
				array_push($path,$stop);
			}
		}
		
		$html->clear();
		unset($html);
		
		$busPath = new BusLinePath($path, $pathID);
		return $busPath;
	}
	
	
		
	
	
	
	
	function getDirectionsForLine($busLine) {
		if ($busLine instanceOf BusLine)
		{
			$atacID = $busStop->getAtacID();
			//$this->paramsWithStopID['id_fermata'] = $atacID; 
			//Costruisco l'url con i parametri giusti
			//$url= ACBusWaitingTimes::$ATAC_URL;
			//foreach($this->paramsWithStopID as $key => $value)
				//$url = $url."&".$key."=".$value;
			$url = "http://muovi.roma.it/paline/palina/".$atacID;
			
			$pageContent = $this->getPageContentAsString($url);
			return $pageContent;
			
		}
		else
			throw new Exception ("ACBusWaitingTimes: Parameters MUST be BusStop type");
		
	}
	
	function test($busStop) {
		$atacID = $busStop->getAtacID();
		//$this->paramsWithStopID['id_fermata'] = $atacID; 
		//Costruisco l'url con i parametri giusti
		//$url= ACBusWaitingTimes::$ATAC_URL;
		//foreach($this->paramsWithStopID as $key => $value)
			//$url = $url."&".$key."=".$value;
		$url = "http://muovi.roma.it/paline/palina/".$atacID;
			
		//echo "<br>".$url;
		$page = $this->getHTMLPageFromURL($url);
		
		$html = str_get_html($page);
		//echo "<br>str_get_html done";
		$html->clear();
		//echo "<br>clear done";
		unset($html);
		//echo "<br>unset done";
		
	}
	
	
	
	function getLinesForStop($busStop) {
		if ($busStop instanceOf BusStop)
		{
			$lines = array();
			$buses = $this->getIncomingBusesAtStop($busStop);
			if ($buses == null) return null;
			foreach ($buses as $bus)
			{
				//Levo i duplicati
				if (!in_array($bus->getLine(),$lines)) {
					array_push($lines,$bus->getLine());
				}
			}
			return $lines;			
		}
		else
		{
			return null;
			//Eccezione
		}
		
	}

	}




?>
